// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-02-01 // namespace LargoCommon.Composer { using Abstract; using JetBrains.Annotations; using LargoCommon.Interfaces; using LargoCommon.Localization; using Music; using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Text; using System.Xml.Serialization; /// Variety of melodic tones. /// Variety of tones. [Serializable] [XmlInclude(typeof(MusicalTone))] public sealed class MusicalVariety : IMusicalVariety { #region Fields /// /// Musical rules. /// private readonly MusicalRules musicalRules; /// /// Musical Bar. /// [NonSerialized] private MusicalBar musicalBar; /// /// Musical Track. /// [NonSerialized] private MusicalElement pieceTrack; /// /// Line rules. /// private ILineRules lineRules; /// /// Melodic Tone. /// private MusicalTone melTone; /// /// Harmonic Structure. /// private HarmonicStructure harmonicStructure; /// /// Single Harmony. /// private bool singleHarmony; /// /// Formal Evaluators. /// [NonSerialized] private DeterminateValue formalEvaluators; /// /// Real Evaluators. /// [NonSerialized] private DeterminateValue realEvaluators; /// /// List of melodic tones. /// private List toneList; /// /// Tone clusters. /// private List toneClusters; #endregion #region Constructors /// /// Initializes a new instance of the MusicalVariety class. Serializable. /// /// The given setup. public MusicalVariety(MusicalSettings givenSettings) { //// LimitCount = DefRhythmicShapeVariety.LimitCount; this.musicalRules = givenSettings.Rules; this.HasTraceValues = givenSettings.HasTraceValues; } /// /// Prevents a default instance of the class from being created. /// private MusicalVariety() { } #endregion #region Public properties - Rules and requests /// /// Gets Line Rules. /// /// Property description. public ILineRules LineRules { get { Contract.Ensures(Contract.Result() != null); if (this.lineRules == null) { throw new InvalidOperationException("Line rules are null."); } return this.lineRules; } private set => this.lineRules = value ?? throw new ArgumentException("Argument cannot be empty.", nameof(value)); } #endregion #region Public properties - Status /// Gets Musical Track. /// Property description. [XmlIgnore] public MusicalElement Element { get { Contract.Ensures(Contract.Result() != null); if (this.pieceTrack == null) { throw new InvalidOperationException("Music piece line is null."); } return this.pieceTrack; } private set => this.pieceTrack = value ?? throw new ArgumentException("Argument cannot be empty.", nameof(value)); } /// /// Gets the line. /// /// /// The line. /// public MusicalLine Line => (MusicalLine)this.Element.Line; /// /// Gets or sets a value indicating whether [trace values]. /// /// /// true if [trace values]; otherwise, false. /// public bool HasTraceValues { get; set; } /// /// Gets or sets the melodic sequence. /// /// /// The melodic sequence. /// private MusicalSequence MelodicSequence { get; set; } /// Gets or sets abstract G-System. /// Property description. [XmlIgnore] //// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Contracts", "Ensures")] private MusicalBar Bar { get { Contract.Ensures(Contract.Result() != null); if (this.musicalBar == null) { throw new InvalidOperationException("Musical bar is null."); } return this.musicalBar; } set => this.musicalBar = value ?? throw new ArgumentException("Argument cannot be empty.", nameof(value)); } /// /// Gets the musical rules. /// /// /// The musical rules. /// private MusicalRules MusicalRules { get { Contract.Ensures(Contract.Result() != null); if (this.musicalRules == null) { throw new InvalidOperationException("Musical rules are null."); } return this.musicalRules; } } #endregion #region Private properties /// Gets abstract G-System. /// Property description. [XmlIgnore] private MusicalTone MusicalTone { get { Contract.Ensures(Contract.Result() != null); if (this.melTone == null) { throw new InvalidOperationException("Musical tone is null."); } return this.melTone; } } /// Gets list of tones. /// Property description. private List ToneList { get { Contract.Ensures(Contract.Result>() != null); if (this.toneList == null) { throw new ArgumentException("ToneList is null."); } return this.toneList; } } /// Gets or sets the recent cluster. /// Property description. private HarmonicCluster RecentCluster { get; set; } /// Gets or sets Main Tone Cluster. /// Property description. private HarmonicCluster MainToneCluster { get; set; } /// Gets or sets list of clusters. /// Property description. private List ToneClusters { get { Contract.Ensures(Contract.Result>() != null); if (this.toneClusters == null) { throw new InvalidOperationException("Tone clusters are null."); } return this.toneClusters; } set => this.toneClusters = value ?? throw new ArgumentException(LocalizedMusic.String("Argument cannot be null."), nameof(value)); } #endregion #region String representation /// String representation of the object. /// Returns value. [UsedImplicitly] public override string ToString() { var s = new StringBuilder(); s.Append("Melodic variety:"); ////\r\n s.Append(this.ToneList.Count.ToString(CultureInfo.CurrentCulture.NumberFormat) + " tones"); ////s.Append(base.ToString()); return s.ToString(); } #endregion #region Public methods /// /// Prepares the variety. /// /// The given line. /// The given bar. /// The given rules. public void PrepareVariety(MusicalElement givenLine, MusicalBar givenBar, ILineRules givenRules) { this.Element = givenLine; this.Bar = givenBar; this.LineRules = givenRules; this.MelodicSequence = new MusicalSequence(this); this.PrepareEvaluators(); } /// Generates possible tones. /// Melodic tone. /// Harmonic modality. /// Harmonic structure. /// Indicate harmonic tones. /// Returns value. public bool GeneratePossibilities(MusicalTone givenTone, BinarySchema harmonicModality, BinaryStructure harmonicStruct, bool harmonyOnly) { Contract.Requires(givenTone != null); Contract.Requires(harmonicModality != null); //// if (givenTone == null) { return false; } //// if (harmonicModality == null) { return false; } this.toneList = new List(); var modalityLevel = harmonicModality.Level; for (byte ml = 0; ml < modalityLevel; ml++) { var e = harmonicModality.PlaceAtLevel(ml); if (harmonyOnly && harmonicStruct != null && harmonicStruct.IsOff(e)) { continue; } //// 2011/11 Now from lower octaves,because higher octaves are preferred by engine (weighed impulse ...] var requestedOctave = this.Element.Status.Octave; var octaveRequest = (short)requestedOctave; //// this.Element.Line.MusicalOctave; octaveRequest = (short)((requestedOctave == MusicalOctave.SubContra) ? octaveRequest + 2 : octaveRequest); octaveRequest = (short)((requestedOctave == MusicalOctave.Contra) ? octaveRequest + 1 : octaveRequest); //// octaveRequest = (short)((octaveRequest == (short)MusicalOctave.FiveLine) ? octaveRequest - 1 : octaveRequest); //// 2016/12 octaveRequest+1 for (var octave = (short)(octaveRequest - 2); octave <= octaveRequest + 1; octave++) { MusicalTone mt = givenTone.Clone() as MusicalTone; if (mt == null) { continue; } mt.Pitch.SetValues(octave, e); mt.ModalityIndex = (short)(ml + (octave * modalityLevel)); if (harmonicStruct != null) { mt.HarmonicIndex = harmonicStruct.LevelOfBit(e); } this.ToneList.Add(mt); } } return this.ToneList.Any(); } /// Returns the next optimal melodic tone. /// Melodic tone. /// Returns value. public MusicalTone OptimalNextMelTone(MusicalTone givenTone) { Contract.Requires(givenTone != null); //// Warning 11 CodeContracts: Member 'LargoObjectMusic.Engine.MelodicVariety.get_MusicalBar' has less visibility than the enclosing method //// 'LargoObjectMusic.Engine.MelodicVariety.OptimalNextMelTone(LargoBase.Music.MusicalTone)'. Contract.Requires(this.Bar.CommonRhythmicShape != null); //// if (givenTone == null) { return null; } this.melTone = givenTone; this.PrepareToneClusters(); this.singleHarmony = false; this.harmonicStructure = this.Bar.HarmonicBar?.PrevailingHarmonicStructure(givenTone.BitRange, out this.singleHarmony); //// (this.Bar.Number) var extremeTotal = -10000000f; MusicalTone bestMelTone = null; short lastToneElement = -1; float formalValue = 0; //// givenTone = mt; not possible! pointer to givenTone is in clusters! //// this.singleHarmony = false; //// this.harmonicStructure = this.Bar.PrevailingHarmonicStructure(givenTone.BitRange, ref this.singleHarmony); foreach (var mt in this.ToneList.Where(mt => mt != null)) { givenTone.SetMelTone(mt); this.Element.PrepareMelInterval(); if (lastToneElement != mt.Pitch.Element) { formalValue = TotalValue(this.formalEvaluators); lastToneElement = givenTone.Pitch.Element; } if (this.Bar.CommonRhythmicShape != null) { var br = givenTone.BitRange; //// (this.Bar.Number) if (br != null) { this.Bar.RecomputeHarmonicClusters(br); } givenTone.OrdinalIndex = mt.OrdinalIndex; //// if lost somewhere ? } float value = TotalValue(this.realEvaluators); var total = formalValue + value; if (this.HasTraceValues) { this.TraceValues(formalValue, mt, value, total); } if (total <= extremeTotal) { continue; } extremeTotal = total; bestMelTone = mt; } if (bestMelTone != null) { //// if (this.TraceValues) { ToneTracer.Singleton.MarkBestTone(bestMelTone, this.Element.Status.LineIndex); } return bestMelTone; } var msg = string.Format( CultureInfo.InvariantCulture, "Requested tone not found in line {0}. Check harmonic modality of the line.", this.Element.Line.LineIndex.ToString(CultureInfo.CurrentCulture.NumberFormat)); throw new InvalidOperationException(msg); } #region Private Static Methods /// /// Total Value. /// /// Set of evaluators. /// Returns value. private static int TotalValue(DeterminateValue evaluators) { if (evaluators == null) { return 0; } var delegates = evaluators.GetInvocationList(); var values = from DeterminateValue member in delegates where member != null select member.Invoke(); return values.Sum(); } #endregion /// /// Traces the values. /// /// The formal value. /// The given tone. /// The value. /// The total. private void TraceValues(float formalValue, MusicalTone givenTone, float value, float total) { Contract.Requires(givenTone != null); if (this.Element.TonePacket == null) { return; } var intendedTone = new IntendedTone { LineIndex = this.Element.Line.LineIndex, MusicalTone = givenTone, HarmonicCoverValue = this.HarmonicCoverValue(), HarmonicValue = this.HarmonicValue(), EasySingValue = this.EasySingValue(), FreeBandValue = this.FreeBandValue(), ImpulseCollisionsValue = this.ImpulseCollisionsValue(), MelodicCollisionsValue = this.MelodicCollisionsValue(), AmbitChangeValue = this.AmbitChangeValue(), OctaveValue = this.OctaveValue(), FiguralValue = this.FiguralValue(), VariabilityValue = this.VariabilityValue(), SequenceValue = this.SequenceValue(), TotalFormalValue = formalValue, TotalRealValue = value, TotalValue = total }; //// DeterminateValue f2 = this.TrackPotentialValue; //// DeterminateValue f3 = this.SensitivePotentialValue; //// DeterminateValue f5 = this.RootValue; //// DeterminateValue f7 = this.IntervalImpulseValue; //// DeterminateValue f9 = this.ParallelConnectionValue; this.Element.TonePacket.IntendedTones.Add(intendedTone); } #endregion #region Bar related values /// Evaluates value of harmonic cover. /// Returns value. private int HarmonicCoverValue() { Contract.Requires(this.Bar.HarmonicBar.RhythmicShape != null); if (this.Bar.HarmonicBar.RhythmicShape == null) { return MusicalQuantity.NeutralValue; } var level = this.Bar.HarmonicBar.RhythmicShape.Level; var total = MusicalQuantity.NeutralValue; for (byte i = 0; i < level; i++) { var harStr = this.Bar.HarmonicBar.HarmonicStructureAtRhythmicLevel(i); if (harStr == null || this.Bar.HarmonicBar.RhythmicShape == null) { continue; } var harRange = this.Bar.HarmonicBar.RhythmicShape.RangeForLevel(i); var harRatio = 1.0f * harRange.Order / this.Bar.Header.System.RhythmicOrder; var stopRange = harRange.StopAt(this.melTone.BitRange.BitTo); //// (this.Bar.Number) if (stopRange == null || stopRange.IsEmpty || this.Element.Tones == null) { continue; } //// 2016/09 Here were melodicBits = 0!? (error) int melodicBits = this.Element.Tones.NumberOfMelodicBits(harStr, stopRange); var allowedBits = stopRange.Length * DefaultValue.HalfUnit; var isSatisfied = !(melodicBits > allowedBits); //// The harmonic values are more important then free band (10*) if (isSatisfied) { ///// this.harmonicStructure.IsOn(this.melTone.Pitch.Element)) { var quotient = (float)melodicBits / harRange.Order; total += (int)(10 * MusicalQuantity.ForcedValue * (1 - quotient) * harRatio); //// ForcedValue } else { var quotient = (float)melodicBits / harRange.Order; total += (int)(10 * MusicalQuantity.HarmfulValue * quotient * harRatio); //// HarmfulValue } } total = total / (level + 1); //// 2014/01 return total; //// if (!isSatisfied) { return MusicalQuantity.PoorValue; } //// return MusicalQuantity.NeutralValue; } /// Evaluates value of free harmonic bands. /// Returns value. private int FreeBandValue() { Contract.Requires(this.melTone != null); //// Contract.Requires(this.MusicalTone.BitRange != null); if (this.melTone.Duration == 0) { return MusicalQuantity.NeutralValue; } var rangeMelodic = 0; var rangeMelodicExists = 0; var rangeTones = 0; //// int rangeTotal = 0; foreach (var harCluster in this.ToneClusters) { if (harCluster == null) { continue; } var bitTotal = harCluster.ToneList.Count; var bitTones = harCluster.NumberOfTrueTones(); var bitEqualTones = harCluster.NumberOfEqualTones(this.melTone.Pitch.Element); if (bitTotal > 1) { //// 2008/07 if (bitEqualTones > 1) { //// 2013 (test >0) rangeMelodicExists += harCluster.CurrentEffectiveLength; } } //// rangeTotal += bitTotal * harCluster.CurrentEffectiveLength; rangeTones += bitTones * harCluster.CurrentEffectiveLength; rangeMelodic += bitEqualTones * harCluster.CurrentEffectiveLength; } //// pitches not existing in sound are preferred var existRatio = this.MusicalTone.Duration > 0 ? (float)rangeMelodicExists / this.MusicalTone.Duration : 1.0f; //// values increased because of importance if (existRatio < DefaultValue.QuarterUnit) { return MusicalQuantity.VeryNiceValue; } //// pitches existing, but rare are preferred 2008/12 //// float equalRatio = rangeTotal > 0 ? (float)rangeMelodic / rangeTotal : DefaultValue.HalfUnit; var equalRatio = rangeTones > 0 ? (float)rangeMelodic / rangeTones : DefaultValue.HalfUnit; //// if (existRatio > DefaultValue.HalfUnit) { //// 2013 && occurenceRatio > DefaultValue.HalfUnit //// For strict 4-part harmonization - quotient>1 needed !? const int quotient = 3; //// 2016/08 was 1, 2015 was 4 return (int)(quotient * MusicalQuantity.PoorValue * (existRatio + equalRatio)); //// } //// return (int)(MusicalQuantity.GoodValue * (1 - occurenceRatio)); //// 2013 test, MusicalQuantity.GoodValue } /// Compute value of impulse collisions of the given tone. /// Returns value. private int ImpulseCollisionsValue() { //// to favor - if the dissonance is prepared by the previous chord //// var test = this.ToneClusters.FirstOrDefault(); //// if (test!=null && test.ValidToneList.Count >=2) { //// float c = test.RealConsonance; float i = test.RealImpulse; float j = test.RealImpulse } var value = 0; // ReSharper disable once LoopCanBeConvertedToQuery foreach (var harCluster in this.ToneClusters) { if (harCluster == null || !harCluster.IsChord) { continue; } var r = harCluster.RealEnergy.Impulse - DefaultValue.Fifty; if (r > 0) { value += (int)(r * MusicalQuantity.PoorValue * harCluster.CurrentEffectiveLength); //// BadValue } } //// 2016 value = value / this.Bar.Header.System.RhythmicOrder; return value; //// (harCluster.RealConsonance < DefaultValue.Fifty) //// PoorValue } /// Compute value of non-harmonic collisions of the given tone. /// Returns value. private int MelodicCollisionsValue() { //// return 0; //// +to favor - if the dissonance is prepared by the previous one var total = 0; // ReSharper disable once LoopCanBeConvertedToQuery foreach (var harCluster in this.ToneClusters) { if (harCluster == null || !harCluster.IsChord) { continue; } var melodicTones = harCluster.MelodicTones(); if (melodicTones == null || melodicTones.Count <= 1) { continue; } total += harCluster.CurrentEffectiveLength; } return total * MusicalQuantity.PoorValue; //// 2016 / this.Bar.Header.System.RhythmicOrder; } /// Compute value of cluster Ambit change. /// Returns value. private int AmbitChangeValue() { const float epsilon = 0.001f; var ambitChange = MusicalQuantity.NeutralValue; if (this.RecentCluster == null) { return ambitChange; } float lastAmbit = this.RecentCluster.FormalAmbit; float ambit = this.MainToneCluster.FormalAmbit; if (Math.Abs(ambit - lastAmbit) > epsilon) { ambitChange += MusicalQuantity.GoodValue; } return ambitChange; } #endregion #region Tone related values /// Determine value of tone according to correspondence with harmony. /// Returns value. private int HarmonicValue() { Contract.Requires(this.Element.Status != null); if (this.harmonicStructure == null) { //// || !this.Element.Status.IsHarmonic return MusicalQuantity.NeutralValue; } var total = MusicalQuantity.NeutralValue; if (this.singleHarmony) { total = !this.harmonicStructure.IsOn(this.MusicalTone.Pitch.Element) ? MusicalQuantity.HarmfulValue : MusicalQuantity.VeryNiceValue; } else { var level = this.Bar.HarmonicBar.RhythmicShape.Level; for (byte i = 0; i < level; i++) { var harStr = this.Bar.HarmonicBar.HarmonicStructureAtRhythmicLevel(i); if (harStr == null || this.Bar.HarmonicBar.RhythmicShape == null) { continue; } var harRange = this.Bar.HarmonicBar.RhythmicShape.RangeForLevel(i); var harRatio = 1.0f * harRange.Order / this.Bar.Header.System.RhythmicOrder; var interRange = harRange.IntersectionWith(this.melTone.BitRange); //// (this.Bar.Number) if (interRange == null || interRange.IsEmpty || this.Element.Tones == null) { continue; } int melodicBits = this.Element.Tones.NumberOfMelodicBits(harStr, harRange); float neededHarmonicBits = harRange.Length; //// The harmonic values are more important then free band (10*) if (melodicBits == 0) { ///// this.harmonicStructure.IsOn(this.melTone.Pitch.Element)) { var quotient = neededHarmonicBits / harRange.Order; total += (int)(10 * MusicalQuantity.ForcedValue * quotient * harRatio); } else { var quotient = (float)melodicBits / harRange.Order; total += (int)(10 * MusicalQuantity.HarmfulValue * quotient * harRatio); } } } //// 2006/06 increased 20 times because of free band increase return total; //// > 0.0f ? MusicalQuantity.ForcedValue : total; } #endregion #region Interval related values /// Property evaluating how easy it is to sing this interval. /// Returns value. private int EasySingValue() { if (this.Element.Status.CurrentMelInterval == null) { return MusicalQuantity.NeutralValue; } var val = this.Element.Status.CurrentMelInterval.EasySing; return val > 0.0f ? MusicalQuantity.NiceValue : MusicalQuantity.PoorValue; } #endregion #region Sequence values /// /// Sequences the value. /// /// Returns value. private int SequenceValue() { return this.MelodicSequence.SequenceValue(); } /// Value of variability. /// Returns value. private int VariabilityValue() { //// to favor tones that differ from previous ones //// just simple test, cycle is time consuming ... //// p += Bar.CountOfUsedPitch(CurrentTone.Pitch); n += Bar.NumberOfTones(); if (this.Line.LastTone == null || this.Line.PenultTone == null || this.Line.CurrentTone == null || this.Line.LastTone.Pitch == null || this.Line.PenultTone.Pitch == null) { return MusicalQuantity.NeutralValue; } var i1 = this.Line.LastTone.Pitch.IntervalFrom(this.Line.PenultTone.Pitch); var i2 = this.Line.CurrentTone.Pitch.IntervalFrom(this.Line.LastTone.Pitch); int v = MusicalQuantity.NeutralValue; var fi1 = this.Element.Bar.Header.System.HarmonicSystem.FormalMedianLength(i1); var fi2 = this.Element.Bar.Header.System.HarmonicSystem.FormalMedianLength(i2); if (fi1 == 0) { v += MusicalQuantity.PoorValue; } else { v += MusicalQuantity.VeryNiceValue; } if (fi2 == 0) { v += MusicalQuantity.PoorValue; } else { v += MusicalQuantity.VeryNiceValue; } return v; } #endregion #region Other Values /// Determine tone value. /// Returns value. private int FiguralValue() { Contract.Requires(this.Element.Status != null); //// 2016/10 Contract.Requires(this.Element.Status.PlannedTones != null); Contract.Requires(this.Element.MusicalLine.CurrentTone != null); //// const int limitDiff = 4; //// 4; var tones = this.Element.Status.MelodicPlan.PlannedTones; if (tones == null || tones.Count == 0) { return MusicalQuantity.NeutralValue; } //// if (!this.Element.Status.HasMelodicMotive) { return MusicalQuantity.NeutralValue; } //// int cnt = this.Element.Line.MusicalTones.Count; //// int plannedCount = this.Element.Line.PlannedTones.Count; //// if (cnt == plannedCount) { var mt1 = this.Line.CurrentTone; //// MusicalTones[cnt - 1] as MusicalTone; if (mt1 == null) { return MusicalQuantity.NeutralValue; } var mt0 = this.Line.LastTone; //// this.Element.Tones.Last(); //// 2016 Status.PreviousTone(mt1); //// MusicalTones[cnt - 1] as MusicalTone; if (mt0 == null) { return MusicalQuantity.NeutralValue; } int idx0 = 0, idx1 = 0; if (this.Element.Tones != null) { idx0 = mt0.OrdinalIndex; //// this.Element.Tones.IndexOf(mt0); idx1 = mt1.OrdinalIndex; //// this.Element.Tones.IndexOf(mt1); } if (idx0 < 0 || idx0 >= tones.Count || idx1 < 0 || idx1 >= tones.Count) { return MusicalQuantity.NeutralValue; } return this.EvaluateFiguralValue(mt1, mt0, idx0, idx1); } /// /// Evaluates the figural value. /// /// The MT1. /// The MT0. /// The index 0. /// The index 1. /// Returns value. private int EvaluateFiguralValue(MusicalTone mt1, MusicalTone mt0, int idx0, int idx1) { Contract.Requires(mt0 != null); Contract.Requires(mt1 != null); if (!(this.Element.Status.MelodicPlan.PlannedTones[idx0] is MusicalTone pmt0) || mt0.IsEmpty || pmt0.IsEmpty || mt1 == null || !(this.Element.Status.MelodicPlan.PlannedTones[idx1] is MusicalTone pmt1) || mt1.IsEmpty || pmt1.IsEmpty) { return MusicalQuantity.NeutralValue; } var distance = mt1.Pitch.SystemAltitude - mt0.Pitch.SystemAltitude; var plannedDistance = pmt1.Pitch.SystemAltitude - pmt0.Pitch.SystemAltitude; var diff = Math.Abs(distance - plannedDistance); //// if (diff > limitDiff) { return MusicalQuantity.NeutralValue; } var value = MusicalQuantity.VeryNiceValue; //// NiceValue value += Math.Sign(distance) == Math.Sign(plannedDistance) ? MusicalQuantity.VeryNiceValue : MusicalQuantity.NiceValue; if (diff > 0) { value -= diff; //// * 10; //// Avoid multiple or conditional return statements. } //// 2016/12 multiply by 5 //// 2017/03 by 10 return value * 10; } /// Determine tone value. /// Returns value. private int OctaveValue() { var octave = this.Element.Status.Octave; var requestedOctave = (short)octave; var mt1 = this.Element.MusicalLine.CurrentTone; //// this.MusicalTone if (mt1 == null) { return MusicalQuantity.NeutralValue; } if (mt1.Pitch.Octave == requestedOctave) { return MusicalQuantity.VeryNiceValue; //// NiceValue; } int order = mt1.Pitch.HarmonicSystem.Order; var requestedAltitude = (requestedOctave + 0.5f) * order; var altitudeDiff = Math.Abs(this.MusicalTone.Pitch.SystemAltitude - requestedAltitude); var mt0 = this.Line.LastTone; if (mt0?.Pitch == null) { return altitudeDiff > order ? MusicalQuantity.PoorValue : MusicalQuantity.NeutralValue; } altitudeDiff = Math.Abs(mt1.Pitch.SystemAltitude - mt0.Pitch.SystemAltitude); if (altitudeDiff > order) { return MusicalQuantity.PoorValue; } return altitudeDiff > order ? MusicalQuantity.PoorValue : MusicalQuantity.NeutralValue; } //// melodic, harmonic, rhythmic variability ... #endregion #region Prepare Evaluators /// /// Prepare Formal Evaluators. /// /// Returns value. private DeterminateValue PrepareFormalEvaluators() { DeterminateValue dv = null; var harmonicRule = false; //// Combined rules if (this.MusicalRules.RuleSimpleHarmony > 0 || this.LineRules.RuleToneHarmonic > 0) { dv += this.HarmonicValue; harmonicRule = true; } //// Engine rules if (!harmonicRule && this.MusicalRules.RuleHarmonicCover > 0) { //// (formalRequest.HasItem(GenProperty.ToneHarmonicCover)) { dv += this.HarmonicCoverValue; } //// Line type rules if (this.LineRules.RuleIntervalEasySing > 0) { dv += this.EasySingValue; } if (this.MusicalRules.RuleFreeBand > 0) { //// (realRequest.HasItem(GenProperty.ClusterFreeBand)) { dv += this.FreeBandValue; } //// if (this.LineRules.RuleToneRoot > 0) { dv += this.RootValue; } return dv; } /// /// Prepare Real Evaluators. /// /// Returns value. private DeterminateValue PrepareRealEvaluators() { DeterminateValue dv = null; //// Engine rules if (this.MusicalRules.RuleImpulseCollisions > 0) { //// (realRequest.HasItem(GenProperty.ClusterImpulseCollisions)) { dv += this.ImpulseCollisionsValue; } //// Moved to formals - RuleFreeBand and RuleParallelConnections if (this.MusicalRules.RuleMelodicCollisions > 0) { //// (realRequest.HasItem(GenProperty.ClusterMelodicCollisions)) { dv += this.MelodicCollisionsValue; } if (this.MusicalRules.RuleAmbitChange > 0) { //// (realRequest.HasItem(GenProperty.ClusterAmbitChange)) { dv += this.AmbitChangeValue; } //// Line type rules dv += this.OctaveValue; //// dv += new DeterminateValue(this.AltitudeValue); if (this.LineRules.RuleMelodicVariability > 0) { dv += this.VariabilityValue; } if (this.LineRules.RuleMelodicFigural > 0) { dv += this.FiguralValue; } if (this.LineRules.MelodicShape != MelodicShape.None) { dv += this.SequenceValue; } return dv; } #endregion #region Other private methods /// /// Prepare Tone Clusters. /// private void PrepareToneClusters() { this.ToneClusters = new List(); var bitFrom = this.MusicalTone.BitFrom; if (bitFrom > 0) { var recentBit = (byte)(bitFrom - 1); this.RecentCluster = this.Bar.HarmonicClusterAtTick(recentBit); } this.MainToneCluster = this.Bar.HarmonicClusterAtTick(bitFrom); var bitTo = this.MusicalTone.BitTo; HarmonicCluster lastHarCluster = null; for (var t = bitFrom; t <= bitTo; t++) { HarmonicCluster harCluster; if (lastHarCluster != null && t < (lastHarCluster.Tick + lastHarCluster.Duration)) { harCluster = lastHarCluster; harCluster.CurrentEffectiveLength++; } else { harCluster = this.Bar.HarmonicClusterAtTick(t); if (harCluster == null) { continue; } harCluster.CurrentEffectiveLength = 1; this.ToneClusters.Add(harCluster); lastHarCluster = harCluster; } } } /// /// Prepare Evaluators. /// private void PrepareEvaluators() { this.formalEvaluators = this.PrepareFormalEvaluators(); this.realEvaluators = this.PrepareRealEvaluators(); } #endregion } }